import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pyplot import *
from pptx import Presentation
from pptx.util import Cm, Pt


class PyJMP:
    def __init__(self, df: pd.DataFrame = pd.DataFrame):
        if not isinstance(df, pd.DataFrame):
            print(OSError('**It should be pass in Dataframe'))
        self.df: pd.DataFrame = df
        self.info = []

    @staticmethod
    def custom_format(y, pos):
        base = y / 10 ** np.floor(np.log10(y))
        return '{:.15g}'.format(y) if base < 8 else ""  # base 控制刻度位置

    def all_AE_limits(self, item='Station ID', breakdown='Version'):
        special_cols = ['Special Build Name', 'Special Build Description', 'Unit Number', 'List of Failing Tests']
        cols = [col for col in self.df.columns if
                self.df[col].dtype in ['float64', 'int64'] and col not in special_cols]
        count = 0
        for col in ['D_H1_H2_CR']:
            plt.gcf().set_size_inches(20, 12)
            info = self.df[item].unique()
            second = self.df[breakdown].unique()
            ttl_data = []
            info1 = []
            info2 = []
            for i in range(len(info)):
                i1_data = self.df[self.df[item] == info[i]]
                print('first:', info[i])
                info1.append(info[i])
                for i2 in range(len(second)):
                    print('second:', info[i2])
                    i2_data = i1_data[i1_data[breakdown] == second[i2]]

                    y = i2_data[col].values
                    x = np.random.normal(1 + count, 0.07, size=len(y))
                    count += 1
                    plt.plot(x, y, color='0.2', marker='o', alpha=1, linestyle='', markersize=3.5)
                    ttl_data.append(i2_data[col].valuse)
                    info2.append(second[i2])
            plt.subplots_adjust(left=0.1, bottom=0.2)
            plt.boxplot(ttl_data,
                        showfliers=False, widths=0.4,
                        boxprops={'color': 'Red', 'markerfacecolor': '#ff000'},
                        capprops={'color': 'red'}, medianprops={'color': 'red'},
                        whiskerprops={'color': 'red'})
            start, height = -0.1, 0.1
            all_info = [info2, info1]

            for info_ in all_info:
                print(info_)
                plt.table(cellText=[[''] * len(info_)],
                          colLabels=info_,
                          cellLoc='center',
                          loc='bottom',
                          bbox=[0, start, 1, height])  # 总厂为1 ， 参数1， 左边宽值为0 ， 参数2:信息上边框的位置，3:右边边框为1 ， 4:信息框下边框的位置
                start -= 0.05
            plt.table(cellText=[[self.df['Site'][0] + '_' + self.df['Product'][0]]],

                      cellLoc='center',
                      loc='bottom',
                      bbox=[0, -0.15, 1, 0.05])  # 总厂为1 ， 参数1， 左边宽值为0 ， 参数2:信息上边框的位置，3:右边边框为1 ， 4:信息框下边框的位置
            plt.ylabel(col, fontsize="large")
            plt.xticks([])
            plt.legend([col], loc='upper right')
            plt.show()
            plt.close()

    # todo
    def x_one_layer(self, x_unique, x_info, cols, selected_key):
        count, ttl_data = 0, []
        print(x_unique)
        for x1 in range(len(x_unique[cols[0]])):  # 遍历x_unique，得到selected_key 所对应的每一个x_unique的值
            x1_data = self.df[self.df[cols[0]] == x_unique[cols[0]]]
        #     y = x1_data[selected_key].dropna().values
        #     if len(y):
        #         x = np.random.normal(1+count , 0.07, size = len(y) )
        #         count += 1
        #         plt.plot(x, y ,color = '0.2' , marker= 'o' , alpha = 1 , linestyle = '' , markersize = 3.5)
        #         ttl_data.append(y)
        #         x_info[f'X{len(x_unique)}'].append({x_unique[cols[-1]][x1_num]:1})
        #     print(x_info)
        # self._boxtplot(plt, ttl_data)
        # for times , key in enumerate(list(x_info.keys()).__reversed__()):
        #     ttl_len= len(x_info[list(x_info.keys())[-1]])
        #     print(ttl_len)
        #     i = 0
        #     for x1 in x_info[key]:
        #         for val , num in x1.items():
        #             val = val.split('__by__')[-1] if '_by_' in val else val
        #             if num :
        #                 plt.table(cellText=[[val]],
        #                           cellLoc='center',
        #                           loc='bottom',
        #                           bbox = [i , -0.05 , -0.05*times , num/ttl_len ,0.05])
        #                 i += num/ttl_len

    def x_two_layer(self, x_unique, x_info, cols, selected_key):
        count, ttl_data = 0, []
        x_index = {f'x{x}': -1 for x in range(1, len(x_unique))}  # 获取总层数（不包含最后一层，最后一层单独处理）
        for x1_num in range(len(x_unique[cols[0]])):  # 遍历x_unique，得到selected_key 所对应的每一个x_unique的值
            x1_info, x1_data = self.split(x1_num, x_unique, cols, x_info, x_index=x_index, index=0)
            for x2_num in range(len(x_unique[cols[1]])):
                x2_info, x2_data = self.split(x2_num, x_unique, cols, x_info, index=1, df_=x1_data)
                y = x2_data[selected_key].dropna().values
                if len(y):
                    x = np.random.normal(1 + count, 0.07, size=len(y))
                    count += 1
                    plt.plot(x, y, color='0.2', marker='o', alpha=1, linestyle='', markersize=3.5)
                    ttl_data.append(y)
                    for num, info in enumerate([x1_info]):
                        x_info[f'X{num + 1}'][x_index[f'x{num + 1}']][info] += 1

                    x_info[f'X{len(x_unique)}'].append({x_unique[cols[-1]][x2_num]: 1})
                print(x_info)
            self._boxtplot(plt, ttl_data)
            for times, key in enumerate(list(x_info.keys()).__reversed__()):
                ttl_len = len(x_info[list(x_info.keys())[-1]])
                print(ttl_len)
                i = 0
                for x1 in x_info[key]:
                    for val, num in x1.items():
                        val = val.split('__by__')[-1] if '_by_' in val else val
                        if num:
                            plt.table(cellText=[[val]],
                                      cellLoc='center',
                                      loc='bottom',
                                      bbox=[i, -0.05, -0.05 * times, num / ttl_len, 0.05])
                            i += num / ttl_len

    def _boxtplot(self, my_plt, data):
        my_plt.boxplot(data,
                       showfliers=False, widths=0.4,
                       boxprops={'color': 'Red', 'markerfacecolor': '#ff000'},
                       capprops={'color': 'red'}, medianprops={'color': 'red'},
                       whiskerprops={'color': 'red'})
        x

    def x_three_layer(self, x_unique, x_info, cols, selected_key):
        count, ttl_data = 0, []
        x_index = {f'x{x}': -1 for x in range(1, len(x_unique))}  # 获取总层数（不包含最后一层，最后一层单独处理）
        for x1_num in range(len(x_unique[cols[0]])):  # 遍历x_unique，得到selected_key 所对应的每一个x_unique的值
            x1_info, x1_data = self.split(x1_num, x_unique, cols, x_info, x_index=x_index, index=0)
            for x2_num in range(len(x_unique[cols[1]])):
                x2_info, x2_data = self.split(x2_num, x_unique, cols, x_info, index=1, x_index=x_index, df_=x1_data,
                                              extra_name=x1_info)
                for x3_num in range(len(x_unique[cols[2]])):
                    x3_info, x3_data = self.split(x3_num, x_unique, cols, x_info, index=2, df_=x2_data)
                    y = x3_data[selected_key].dropna().values
                    if len(y):
                        x = np.random.normal(1 + count, 0.07, size=len(y))
                        count += 1
                        plt.plot(x, y, color='0.2', marker='o', alpha=1, linestyle='', markersize=3.5)
                        ttl_data.append(y)
                        for num, info in enumerate([x1_info]):
                            x_info[f'X{num + 1}'][x_index[f'x{num + 1}']][info] += 1
                        x_info[f'X{len(x_unique)}'].append({x_unique[cols[-1]][x3_num]: 1})
                print(x_info)

            self._boxtplot(plt, ttl_data)
            for times, key in enumerate(list(x_info.keys()).__reversed__()):
                ttl_len = len(x_info[list(x_info.keys())[-1]])
                print(ttl_len)
                i = 0
                for x1 in x_info[key]:
                    for val, num in x1.items():
                        val = val.split('__by__')[-1] if '_by_' in val else val
                        if num:
                            plt.table(cellText=[[val]],
                                      cellLoc='center',
                                      loc='bottom',
                                      bbox=[i, -0.05, -0.05 * times, num / ttl_len, 0.05])
                            i += num / ttl_len

    def split(self, num, x_unique, cols, x_info, x_index=None, index=0, df_=None, extra_name=None):
        x_name = f'{extra_name}_by_{x_unique[cols[index]][num]}' if extra_name else x_unique[cols[index]][num]
        if isinstance(df_, pd.DataFrame):
            data = df_[df_[cols[index]] == x_unique[cols[index]][num]]
        else:
            data = self.df[self.df[cols[index]] == x_unique[cols[index]][num]]
        if index < len(x_unique) - 1:
            x_info[f'X{index + 1}'].append({x_name: 0})
        if x_index:
            x_index[f'x{index + 1}'] += 1

        return x_name, data

    def x_four_layer(self, x_unique, x_info, cols, selected_key):
        count, ttl_data = 0, []
        x_index = {f'x{x}': -1 for x in range(1, len(x_unique))}  # 获取总层数（不包含最后一层，最后一层单独处理）
        for x1_num in range(len(x_unique[cols[0]])):  # 遍历x_unique，得到selected_key 所对应的每一个x_unique的值
            x1_info, x1_data = self.split(x1_num, x_unique, cols, x_info, x_index=x_index, index=0)
            for x2_num in range(len(x_unique[cols[1]])):
                x2_info, x2_data = self.split(x2_num, x_unique, cols, x_info, index=1, x_index=x_index, df_=x1_data,
                                              extra_name=x1_info)
                for x3_num in range(len(x_unique[cols[2]])):
                    x3_info, x3_data = self.split(x3_num, x_unique, cols, x_info, index=2, x_index=x_index, df_=x2_data
                                                  , extra_name=x2_info)
                    for x4_num in range(len(x_unique[cols[3]])):
                        x4_info, x4_data = self.split(x4_num, x_unique, cols, x_info, index=3, df_=x3_data)
                        y = x4_data[selected_key].dropna().values
                        if len(y):
                            x = np.random.normal(1 + count, 0.07, size=len(y))
                            count += 1
                            plt.plot(x, y, color='0.2', marker='o', alpha=1, linestyle='', markersize=3.5)
                            ttl_data.append(y)
                            print('ok1', self.info)
                            print('ok2', x1_info, x2_info, x3_info)

                            for num, info in enumerate([x1_info, x2_info.x3_info]):
                                x_info[f'X{num + 1}'][x_index[f'x{num + 1}']][info] += 1
                            x_info['X4'].append({x_unique[cols[-1]][x4_num]: 1})
                            # x_info[f'X{len(x_unique)}'].append({x_unique[cols[-1]][x3_num]: 1})

                self.info.clear()

        self._boxtplot(plt, ttl_data)
        for times, key in enumerate(list(x_info.keys()).__reversed__()):
            ttl_len = len(x_info[list(x_info.keys())[-1]])
            print(ttl_len)
            i = 0
            for x1 in x_info[key]:
                for val, num in x1.items():
                    val = val.split('__by__')[-1] if '_by_' in val else val
                    if num:
                        plt.table(cellText=[[val]],
                                  cellLoc='center',
                                  loc='bottom',
                                  bbox=[i, -0.05, -0.05 * times, num / ttl_len, 0.05])
                        i += num / ttl_len

    def test(self, cols: list):
        layer_dict = {1: self.x_one_layer, 2: self.x_two_layer, 3: self.x_three_layer,
                      4: self.x_four_layer}
        for col in ['D_H1_H2_CR']:
            self.df['D_H1_H2_CR'].dropna(inplace=True)
            plt.gcf().set_size_inches(20, 12)
            x_unique = {col: self.df[col].dropna().unique() for col in cols}
            x_info = {fr'X{1 + num} ': [] for num in range(len(cols))} if len(cols) > 1 else {}
            plt.subplots_adjust(left=0.1, bottom=0.2)
            layer_dict[len(cols)](*[x_unique, x_info, cols, col])
            plt.ylabel(col, fontsize="large")
            plt.xticks([])
            plt.legend([col], loc='upper right')
            plt.show()
            plt.close()


if __name__ == '__main__':
    df = pd.read_csv(r"path")
    jmp = PyJMP(df)
    jmp.test(['station ID', "product"])
